#include "sudoku.h"
#include "assert.h"
sudoku::sudoku()
{
	do 
	{
		cout << "Inserisci la dimensione:\n1 per 3x3\n2 per 4x4\n3 per 5x5\n";
		cin >> dim;
	} 
	while (dim > 2 && dim < 6);
	
	dim = dim + 2;

	griglia.resize(dim * dim, dim * dim);
	gioco.resize(dim * dim, dim * dim);
	
	for (int i = 0; i < dim * dim; i++)
	{
		for (int j = 0; j < dim * dim; j++)
		{
			griglia.at(i,j).card = gioco.at(i,j).card = dim * dim;
			griglia.at(i,j).numero = gioco.at(i,j).numero = 0;
			
			gioco.at(i,j).insieme.resize(dim * dim);
			griglia.at(i,j).insieme.resize(dim * dim);
			
			for (int k = 0; k < dim * dim; k++) 
			{
				griglia.at(i,j).insieme.at(k) = false;
				gioco.at(i,j).insieme.at(k) = false;
			}
		}
	}
}

void sudoku::rimuovi_possibilita(int riga, int col, int num)
{
	for (int i = 0; i < dim * dim; i++)
	{
		if (!griglia.at(i,col).insieme.at(num)) 
		{
			griglia.at(i,col).insieme.at(num) = true;
			griglia.at(i,col).card--;
		}

		if (!griglia.at(riga,i).insieme.at(num)) 
		{
			griglia.at(riga,i).insieme.at(num) = true;
			griglia.at(riga,i).card--;
		}
	}
	
	for (int i = (riga / dim) * dim; i < (riga / dim) * dim + dim; i++) 
	{
		for (int j = (col / dim) * dim; j < (col / dim) * dim + dim; j++)
		{
			if (!griglia.at(i,j).insieme.at(num)) 
			{
				griglia.at(i,j).insieme.at(num) = true;
				griglia.at(i,j).card--;
			}
		}
	}
}

void sudoku::aggiungi_possibilita(int riga, int col, int num)
{
	for (int i = 0; i < dim * dim; i++)
	{
		if (griglia.at(i,col).insieme.at(num)) 
		{
			griglia.at(i,col).insieme.at(num) = false;
			griglia.at(i,col).card++;
		}

		if (griglia.at(riga,i).insieme.at(num)) 
		{
			griglia.at(riga,i).insieme.at(num) = false;
			griglia.at(riga,i).card++;
		}
	}
	
	for (int i = (riga / dim) * dim; i < (riga / dim) * dim + dim; i++) 
	{
		for (int j = (col / dim) * dim; j < (col / dim) * dim + dim; j++)
		{
			if (griglia.at(i,j).insieme.at(num)) 
			{
				griglia.at(i,j).insieme.at(num) = false;
				griglia.at(i,j).card++;
			}
		}
	}
}

void sudoku::genera_tabella()
{
	vector< table<casella> > v;
	vector<passo> p;
	int min = 0, riga = 0, col = 0, numero;
	
	inserisci_random();
	v.push_back(griglia);
	
	for (;;) 
	{
		min = possibilita_minima(riga, col);
		if (min == 100) return;

		numero = trova_libero(riga, col);
		cerr << "(" << min << "," << numero << "," << riga << "," << col << ")";
	
		if (/*min == 0 || */numero == 0) // se non trovo una riga da assegnare: COSA SERVE min???
		{
			cerr << endl;
			
			assert(!p.empty());
			riga = p.back().riga;
			col = p.back().col;
			p.pop_back();
			
			cerr << riga << " " << col << endl; assert(riga < griglia.rows() && col < griglia.cols());
			numero = griglia.at(riga,col).numero;
			//assert(!v.empty());
			//v.pop_back();
			
			//griglia = v.back();
			griglia.at(riga,col).numero = 0;
			//griglia.at(riga,col).card--;
			griglia.at(riga,col).insieme.at(numero - 1) = true;
			aggiungi_possibilita(riga, col, numero - 1); // CREATO
		} 
		else
		{
			cerr << " ";
			
			p.push_back(passo(riga, col));
			
			// numero = trova_libero(riga, col); <- INUTILE, da rimuovere
			griglia.at(riga, col).numero = numero;
			griglia.at(riga,col).card--; // AGGIUNTO
			rimuovi_possibilita(riga, col, numero - 1);
			
			//v.push_back(griglia);
		}
	}
}

int sudoku::possibilita_minima(int &riga, int &col)
{
	int min = 100;
	for (int i = 0; i < dim * dim; i++) 
	{
		for (int j = 0; j < dim * dim; j++) 
		{
			if (griglia.at(i,j).numero == 0 && griglia.at(i,j).card < min) 
			{
				min = griglia.at(i,j).card;
				riga = i;
				col = j;
			}
		}
	}
	return min;
}

int sudoku::possibilita_massima(int &riga, int &col)
{
	int max=0;
	for(int i=0; i<dim*dim; i++) {
		for(int j=0; j<dim*dim; j++) {
			if(griglia.at(i,j).numero==0 && griglia.at(i,j).card>max) {
				max=griglia.at(i,j).card;
				riga=i;
				col=j;
			}
		}
	}
	return max;
}
void sudoku::stampa_soluzione_sudoku()
{
	char k=56;
	cout <<"   ";
	for(int i=0; i<dim*dim; i++) {
		if(i>0 && i%dim==0)
			cout << " ";
		if(i>=9)
			cout << char (i+k)<<" ";
		else
			cout << i+1 << " ";
	}
	cout<<"\n\n";
	for(int i=0; i<dim*dim; i++) {
		if(i>0 && i%dim==0)
			cout << " \n";
		if(i>=9)
			cout << char(i+k) << "  ";
		else
			cout << i+1 << "  ";
		for(int j=0; j<dim*dim; j++) {
			if(j>0 && j%dim==0)
				cout << " ";
			if(griglia.at(i,j).numero>9)
				cout <<char (griglia.at(i,j).numero+k) << " ";
			else
				cout << griglia.at(i,j).numero << " ";
		}
		cout << "\n";
	}
}

void sudoku::inserisci_random()
{
	srand(time(0));
	
	int riga, col, num, i = 0;
	
	while (i <= (dim * dim))
	{
		riga = rand() % (dim * dim);
		col = rand() % (dim * dim);
		num = rand() % (dim * dim) + 1;
		if (!griglia.at(riga, col).insieme.at(num - 1))
		{
			griglia.at(riga, col).numero = num;
			rimuovi_possibilita(riga, col, num - 1);
			i++;
		}
	}
}

int sudoku::trova_libero(int riga,int col)
{
	for (int i = 0; i < dim * dim; i++) 
	{
		if (!griglia.at(riga, col).insieme.at(i)) return i + 1;
	}
	return 0;
}
